classdef ParametricMagnetometer < EquipmentControl.SystemlMachine.AbstractSystemMachine
    %PARAMETRICMAGNETOMETER Summary of this class goes here
    %   Detailed explanation goes here
    
    properties
        master
        slave

    end
    
    methods
        function obj = ParametricMagnetometer(session, varargin)
            %PARAMETRICMAGNETOMETER Construct an instance of this class
            %   Detailed explanation goes here
            obj@EquipmentControl.SystemlMachine.AbstractSystemMachine(session);

            %%%%%%%%%%%%%%
            p=inputParser;
            p.addParameter('master', 'dev3543', @ischar);
            p.addParameter('slave',  'dev3560', @ischar);
            p.parse(varargin{:});
            
            obj.master = p.Results.master;
            obj.slave = p.Results.slave;
            %%%%%%%%%%%%%%

            obj.control_variables = {'aom_amplitude', ...
                                     'aom_frequency', ...
                                     'aom_offset', ...
                                     ...
                                     'eater_offset', ...
                                     ...
                                     'x4coil_amplitude', ...
                                     'x4coil_frequency', ...
                                     'x4coil_offset', ...
                                     ...
                                     'x5coil_offset', ...
                                     ...
                                     'ycoil_offset', ...
                                     ...
                                     'z1coil_amplitude', ...
                                     'z1coil_frequency', ...
                                     'z1coil_offset', ...
                                     ...
                                     'z9coil_offset' };
                                 
            obj.monitor_variables = {'pump_power', ...
                                     'probe_power' };
            
            obj.getDevices();
            obj.system_initialize();
        end
        
        %% device initialization
        function obj = getDevices(obj)
            obj.dev.ziMaster = obj.session.getDevice(obj.master);
            obj.dev.ziSlave = obj.session.getDevice(obj.slave);
%             obj.dev.tek = obj.session.getDevice('tek');
%             obj.dev.aom = EquipmentControl.ExecutionEquipment.AOM.AA('Pump Modulation');
%             obj.dev.aom.controlledBy(obj.dev.tek, 1).setWave(); 
            
            path = [current_file_path(mfilename('fullpath')) '/ziConfig/' ];
            
            obj.dev.ziMaster.loadSettings([path 'Dev3543NMRGyro.xml']);
            obj.dev.ziSlave.loadSettings([path 'Dev3560NMRGyro.xml']);
        end
        
        function obj = system_initialize(obj)
%             obj.setAOM_DC_Voltage( 5.0 ); % pump beam intensity control
            
            % x coils
            obj.setX4CoilOffset( 0.0 ); % main field DC control
            obj.disableX5CoilModulation();
            obj.setX5CoilFrequency( 34e3 ).setX5CoilAmplitude( 4.0 ).setX5CoilOffset( 0.0 );  % parametric modulation field
            
            % y coils
            obj.setYCoilOffset( 0.2 ); % y field DC control
            
            % z coils
            obj.setZ9CoilOffset( ); % manually contorlled - DC
            obj.disableZ1CoilModulation();
            obj.setZ1CoilAmplitude(1:4, [13.08e-3, 58.88e-3, 50.0e-3, 0.0]); 
           
            % demod signals
            obj.setSingal_DemodPhase('0', 0.0);
            obj.setSignal_By_fine('osc', 0, 'order', 3, 'bw', 5.0, 'rate', 1.0e3);
            obj.setSignal_By('osc', 0, 'order', 3, 'bw', 100.0, 'rate', 2.0e3);
            obj.setSignal_Bz('osc', 0, 'order', 3, 'bw', 100.0, 'rate', 2.0e3);
        end
        
        %% set X Coils
        % x4 coil
        function obj = setX4CoilOffset(obj, val)
             obj.dev.ziSlave.setAuxOutOffset('0', val);
        end
        
        % on/off
        function obj = enableX5CoilModulation(obj)
            obj.dev.ziMaster.fireSigOut()
        end
        function obj = disableX5CoilModulation(obj)
            obj.dev.ziMaster.silenceSigOut();
        end

        % amplitude
        function obj = setX5CoilAmplitude(obj, val)
            obj.dev.ziMaster.disableOutAmplitude();
            obj.dev.ziMaster.setSigOutAmplitude('0', val);
        end
        
        % frequency
        function obj = setX5CoilFrequency(obj, val)
            obj.dev.ziMaster.setOscFreq('0', val);
        end
        
        % offset
        function obj = setX5CoilOffset(obj, val)
            obj.dev.ziMaster.setSigOutOffset(val);
        end
        

        %% Set Y Coils
        function obj = setYCoilOffset(obj, val)
             obj.dev.ziMaster.setAuxOutOffset('2',val);
        end
        
        %% Control Z Coils
        % on/off
        function obj = enableZ1CoilModulation(obj)
            obj.dev.ziSlave.fireSigOut();
        end
        function obj = disableZ1CoilModulation(obj)
            obj.dev.ziSlave.silenceSigOut();
        end
        
        % amplitude - multi-mode modulation
        function obj = setZ1CoilAmplitude(obj, ch, val)
            if obj.eqLength(ch, val)
                arrayfun( @(x, y) obj.dev.ziSlave.setSigOutAmplitude( num2str(x-1), y ), ch, val, 'UniformOutput', false);
            end
        end
        function obj = disableZ1CoilAmplitude(obj, ch)
            if nargin == 1
                obj.dev.ziSlave.disableOutAmplitude();
            else
                obj.dev.ziSlave.disableOutAmplitude(ch);
            end
        end
        function obj = enableZ1CoilAmplitude(obj, ch)
            if nargin == 1
                obj.dev.ziSlave.enableOutAmplitude();
            else
                arrayfun( @(x) obj.dev.ziSlave.enableOutAmplitude( num2str(x-1) ), ch, 'UniformOutput', false);
            end
        end
        
        % frequency
        function obj = setZ1CoilFrequency(obj, ch, val)
            if obj.eqLength(ch, val)
                arrayfun( @(x, y) obj.dev.ziSlave.setOscFreq( num2str(x-1), y ), ch, val, 'UniformOutput', false);
            end
        end
        
        %offset
        function obj = setZ1CoilOffset(obj, val)
            obj.dev.ziSlave.setSigOutOffset(val);
        end
        
        %range
        function obj = setZ1ControlRange(obj, range)
            ziDAQ('setDouble', ['/' obj.slave '/sigouts/0/range'], range);
        end
        
        function obj = setZ9CoilOffset(obj, ~)
            % manually controlled. current = 6.0 mA - 20180509
        end
        
        %% Set AOM
        function obj = setAOM_DC_Voltage(obj, volt)
            obj.dev.aom.voltage_on = volt;
            obj.dev.aom.dcON();
        end
        
        function obj = setAOMAmplitude(obj, val)
        end
        function obj = setAOMFrequency(obj, val)
        end
        function obj = setAOMOffset(obj, val)
        end
        
        function obj = setEaterOffset(obj, val)
        end
        
        
        %% Signal By_fine, By, Bz
        function obj = setSignal_By_fine(obj, varargin)
            p=inputParser;
            oscTest = @(x) ismember(x, 0:3);
            phaseTest = @(x) x >= 0 && x <= 360.0;
            OrderTest = @(x) ismember(x, 1:8);
            bwTest = @(x) x > 0 && x < 10e3;
            
            p.addParameter('osc', 0, oscTest);
            p.addParameter('phase', 0, phaseTest);
            p.addParameter('order', 3, OrderTest);
            p.addParameter('bw', 5.0, bwTest);
            p.addParameter('rate', 2e3, bwTest);
            p.parse(varargin{:});
            
            ch = '1';
            obj.setSignal_Osc(ch , p.Results.osc)...
               .setSingal_DemodPhase(ch, p.Results.phase)...
               .setSignal_DemodOrder(ch , p.Results.order)...
               .setSignal_DemodBW(ch , p.Results.bw)...
               .setSignal_DataRate(ch , p.Results.rate);
        end
        
        function obj = setSignal_By(obj, varargin)
            p=inputParser;
            oscTest = @(x) ismember(x, 0:3);
            phaseTest = @(x) x >= 0 && x <= 360.0;
            OrderTest = @(x) ismember(x, 1:8);
            bwTest = @(x) x > 0 && x < 10e3;
            
            p.addParameter('osc', 0, oscTest);
            p.addParameter('phase', 0, phaseTest);
            p.addParameter('order', 3, OrderTest);
            p.addParameter('bw', 100.0, bwTest);
            p.addParameter('rate', 2e3, bwTest);
            p.parse(varargin{:});
            
            ch = '2';
            obj.setSignal_Osc(ch , p.Results.osc)...
               .setSingal_DemodPhase(ch, p.Results.phase)...
               .setSignal_DemodOrder(ch , p.Results.order)...
               .setSignal_DemodBW(ch , p.Results.bw)...
               .setSignal_DataRate(ch , p.Results.rate);
        end
        
        function obj = setSignal_Bz(obj, varargin)
            p=inputParser;
            oscTest = @(x) ismember(x, 0:3);
            phaseTest = @(x) x >= 0 && x <= 360.0;
            OrderTest = @(x) ismember(x, 1:8);
            bwTest = @(x) x > 0 && x < 10e3;
            
            p.addParameter('osc', 0, oscTest);
            p.addParameter('phase', 0, phaseTest);
            p.addParameter('order', 3, OrderTest);
            p.addParameter('bw', 100.0, bwTest);
            p.addParameter('rate', 2e3, bwTest);
            p.parse(varargin{:});
            
            ch = '3';
            obj.setSignal_Osc(ch , p.Results.osc)...
               .setSingal_DemodPhase(ch, p.Results.phase)...
               .setSignal_DemodOrder(ch , p.Results.order)...
               .setSignal_DemodBW(ch , p.Results.bw)...
               .setSignal_DataRate(ch , p.Results.rate);
        end
        
        function obj = setSignal_Osc(obj, ch, osc)
            obj.dev.ziMaster.setSigOutOscSelect(ch, osc);
        end
        function obj = setSingal_DemodPhase(obj, ch, phase)
            obj.dev.ziMaster.setDemodPhase(ch, phase);
        end
        function obj = setSignal_DemodOrder(obj, ch, order)
            obj.dev.ziMaster.setDemodFilterOrder(ch, order).enableDataTransfer(ch);
        end
        function obj = setSignal_DemodBW(obj, ch, bw)
            obj.dev.ziMaster.setDemodFilterBW(ch, bw).enableDataTransfer(ch);
        end
        function obj = setSignal_DataRate(obj, ch, rate)
            obj.dev.ziMaster.setDataTranferRate(ch, rate).enableDataTransfer(ch);
        end

        %% show monitor_variables
        function obj = showPumpPower(obj, hdl, rate)
        end
        function obj = showProbePower(obj, hdl, rate)
        end
        
        %% recover Working point
        function recover_working_piont(obj, phase_data)
            sess = obj.session;  zi=sess.getDevice(obj.master);
            
            demod_chY = '2'; demod_chZ = '3';
            zi.setDemodPhase(demod_chY, phase_data.optPhaseY);
            zi.setAuxOutOffset(demod_chY, phase_data.optBiasY);

            zi.setDemodPhase(demod_chZ, phase_data.optPhaseZ);
            zi.setAuxOutOffset(demod_chZ, phase_data.optBiasZ);
        end
    end
    
    %% machine operations
    methods
        res =setDemodPhase(obj, varargin)
        res = getStdSpectrum(obj, varargin)
        res = getProbeSignal(obj, varargin)
        res = getPumpPower(obj, varargin)
    end
    
    methods (Access = private)
        function res = eqLength(~, x, y)
            if length(x) ~= length(y)
                error('Input arrays have different lengths.');
            end
            res = true;
        end

    end
end

